import time
import copy
import threading
import importlib
import traceback

from lib import log

class World(object):
	def __init__(self, packageName):
		self._objects = []
		self._loadedClasses = {}
		self._packageName = packageName
		
	def initGame(self):
		pass # do nothing - override if you have special game init logic
	
	def finalizeGame(self):
		log.info("removing all objects from the game world")
		self.removeAll()
	
	@property
	def rootPackage(self): return self._packageName
	@property
	def objectsPackage(self): return self.rootPackage + ".objects"
	@property
	def commandsPackage(self): return self.rootPackage + ".commands"
	
	def addObject(self, obj):
		self._objects.append(obj)
		obj.comeAlive()
	
	def addObjectByName(self, name):
		# to do: check to see if this object is already known
		object_class = self.loadObject(name)
		if not object_class:
			log.error("object class for '{0}' could not be loaded".format(name))
			return None
		try:
			new_object = object_class()
			return self.addObject(new_object)
		except Exception as e:
			log.error(traceback.format_exc())
			log.error("Could not instantiate '{0}'".format(name))
			return None
			
	def removeAll(self):
		removeList = copy.copy(self._objects)
		for obj in removeList:
			self._objects.remove(obj)
			obj.die()
	def heartbeat(self):
		for world_object in self._objects:
			world_object.heartbeat()

	def loadObject(self, name, reload=False):
		# 1. check to see if the object is already loaded and reload is false
		log.info("Checking whether {0} object already loaded".format(name))
		if name in self._loadedClasses:
			if not reload:
				log.info("{0} object already loaded".format(name))
				return self._loadedClasses[name]
			else:
				log.info("{0} object already loaded - removing for reload".format(name))
				del self._loadedClasses[name]
				
		# 2. load this via python import
		try:
			imported_module = importlib.import_module(self.rootPackage + '.' + name)
		except Exception as e:
			log.error(traceback.format_exc())
			imported_module = None
		
		name_parts = name.split('.')
		object_name = name_parts[-1] # the last part
		
		object_class = None
		if imported_module:
			object_class = getattr(imported_module, object_name)
			if object_class: self._loadedClasses[name] = object_class
		
		return object_class
		
class WorldProcessingThread(threading.Thread):
	def __init__(self, world):
		super(WorldProcessingThread, self).__init__()
		self._world = world
		self._stop = threading.Event()

	def stop(self):
		self._stop.set()

	def run(self):
		log.info("Starting the world...")
		while not self._stop.is_set():
			self._world.heartbeat()
			time.sleep(3)
		log.info("Shutting down the world...")

